Modern Python part 3: CIパイプラインの実行とPyPIへのパッケージの公開
著者:Faouzi BRAZA Jun 28, 2021
はじめに
メンテナンスの行き届いた使い勝手の良いPythonパッケージをオープンソースコミュニティや社内に提案するためには、一連の重要なステップを達成することが求められます。まず、あなたのコードがユニットテストされていることを確認してください。第二に、一般的な文章やフォーマットのスタイルを尊重することです。これらのステップを自動化し、継続的な統合パイプラインに統合することで、ソースコードの修正に起因するリグレッションを回避します。最後に、将来のユーザーのために十分なドキュメントを提供します。Pythonパッケージが完成したら、Python Package Index (PyPI)で公開するのが一般的です。ここでは、Poetry、Tox、GitHub Actionsを使って、これらのステップを実行する方法を見ていきます。今回のユースケースで使用したコードは、私たちのリポジトリにあります。
この記事は、ベストプラクティスを紹介する3つのシリーズの最後の記事です。
日本語訳:Modern Python part 3: CIパイプラインの実行とPyPIへのパッケージの公開
toxによるリンターチェックとテストの自動化
まだ仮想環境を起動していない場合は、次のように起動します。
code: bash
$ poetry shell
コードの適合性をチェックするために、コードが一般的なPythonのライティングガイドラインを尊重しているかどうかを評価するいくつかのパッケージを使用しています。そして、それらの実行とユニットテストを自動化するために、toxを使用します。これらのパッケージをインストールするには、次のように実行します。
code: bash
$ poetry add black flake8 pylint tox --dev
toxとpoetryは、もともと相性が悪く、やや冗長になってしまいます。両者を一緒に使うには、いくつかのトリックを実装する必要があります(issue1941 とissue1745 を参照)。 toxは、タスクを実行するために独自の環境と依存関係をインストールします。しかし、依存関係をインストールするためには、toxの設定で poetry install というコマンドを宣言する必要があります。これは冗長性をもたらし、いくつかの問題を引き起こす可能性があります。さらに、これではテストの実行に必要な開発者の依存関係をインストールすることができません。toxにpoetry.lockファイルを使わせて、必要な依存関係をインストールさせた方が生産的です。そのためには、これらの問題を解決するために開発された tox-poetry-installer パッケージを使用することをお勧めします。 code: bash
$ poetry add tox-poetry-installerpoetry --dev ここで、toxの設定を tox.ini ファイルで宣言します。その内容は以下の通りです。
code: tox.ini
envlist = py38
isolated_build = true
description = Linting, checking syntax and running tests
require_locked_deps = true
install_dev_deps = true
commands =
poetry run black summarize_dataframe/summarize_df.py
poetry run flake8 summarize_dataframe/summarize_df.py
poetry run pylint summarize_dataframe/summarize_df.py
poetry run pytest -v
ここでは2つのセクションを見ることができます。
[tox]: テスト環境のPythonバージョンを含む、tox自動化パイプラインのグローバル設定を定義します。
[testenv]: テスト環境を定義します。require_locked_deps は、依存関係をインストールするために tox が poetry.lock ファイルを利用するかどうかを選択します。install_dev_deps は、開発者の依存関係をインストールするかどうかを選択します。
tox パイプラインを実行します。
code: bash
$ tox
# shorten for brevety ... py38 run-test: commands0 | poetry run black summarize_dataframe/summarize_df.py All done! ✨ 🍰 ✨
1 file left unchanged.
py38 run-test: commands1 | poetry run flake8 summarize_dataframe/summarize_df.py py38 run-test: commands2 | poetry run pylint summarize_dataframe/summarize_df.py ************* Module summarize_dataframe.summarize_df
summarize_dataframe/summarize_df.py:1:0: C0114: Missing module docstring (missing-module-docstring)
summarize_dataframe/summarize_df.py:4:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
summarize_dataframe/summarize_df.py:11:4: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
summarize_dataframe/summarize_df.py:23:4: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
summarize_dataframe/summarize_df.py:43:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
------------------------------------------------------------------
Your code has been rated at 7.62/10 (previous run: 7.62/10, +0.00)
ERROR: InvocationError for command /home/fbraza/Documents/python_project/summarize_dataframe/.tox/py38/bin/poetry run pylint summarize_dataframe/summarize_df.py (exited with code 16)
________________________________________________________ summary ________________________________________________________________
ERROR: py38: commands failed
完璧です。toxの自動化パイプラインはローカルで成功しました。次のステップでは、GitHub Actions を使った CI パイプラインを実装します。
GitHub Actions による継続的インテグレーション
GitHub Actions は、ソフトウェアのワークフローを簡単に自動化できるサービスです。このサービスはイベント駆動型で、特定のイベントが発生したときに一連のコマンドが実行されます。そのようなイベントとは、ブランチにプッシュされたコミットやプルリクエストなどです。GitHub Actionsは、自分のコードに対して必要なテストを実行するのにとても便利です。
最も重要なのは、GitHub Actions があれば Python パッケージを複数の Python バージョンや異なる OS (Linux、macOS、Windows) でテストできるということです。必要なのは、既存のリポジトリと .github/workflows/ci.yaml ファイルだけです。
code: bash
$ mkdir -p .github/workflows
$ touch .github/workflows/ci.yml
.github/workflows/ci.yml を次のように記述します。
code: .github/workflows/ci.yml
name: CI Pipeline for summarize_df
on:
- push
- pull_request
jobs:
build:
runs-on: ${{matrix.platform}}
strategy:
matrix:
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install poetry
poetry install
- name: Test with tox
run: poetry run tox
それぞれのフィールドについて少し説明します。
on: このフィールドは、パイプラインのトリガーとなるイベントの種類を定義します。
jobs: このフィールドは、パイプラインの複数のステップを定義します。仮想環境のインスタンスで実行されます。
build: ここですべてのマジックが起こります。
strategy.matrix.platform フィールドでは、パッケージのテストに使用する異なるOSを定義します。これらの値をbuild.run-on フィールド(${{matrix.platform}})に渡すためにテンプレートを使用します。
strategy.matrix.python-version フィールドは、パッケージのテストに使用したいPythonの異なるバージョンを定義します。
steps フィールドでは、使用するアクション(steps.uses)と、実行するコマンド(steps.run)を指定します。
最後に、tox.ini と pyporject.toml ファイルを適宜変更します。当初、toxにはPythonの3.8バージョンを選択しました。しかし、3.7や3.9との互換性を持たせたいと思います。pyproject.tomlファイルでは、パッケージと互換性のあるバージョンを選択します。ここでは、3.7.1以上との互換性を持つようにしています。以下は、私たちのファイルに追加された変更点です。
code: 抜粋 tox.ini
envlist = py37,py38,py39
isolated_build = true
skip_missing_interpreters = true
code: 抜粋 pyproject.toml
python = "^3.7.1"
pyproject.toml ファイルを修正する際には、常にpoetry updateコマンドを実行してください。このコマンドは、あなたの依存関係と使用したいPythonのバージョンとの間の予期せぬ非互換性をチェックすることができます。
最後に、tox-gh-actionsというパッケージをインストールして、複数のバージョンのPythonを使用しながらGitHub上でtoxを並行して実行します。
code: bash
$ poetry add tox-gh-actions --dev
パイプラインの準備が整いました。変更を追加、コミット、プッシュすると、パイプラインが実行されます。
code: bash
$ echo "!.github/" >> .gitignore
$ git add .gitignore
$ git commit -m "build: update .gitignore to unmask .github/ folder"
$ git add pyproject.toml tox.ini poetry.lock .github/workflows/ci.yml
$ git commit -m "build: tox pipeline + github actions CI pipeline"
GitHubリポジトリにアクセスし、Actionsタブをクリックします。
https://gyazo.com/f7547fe47c6d4306e17f5b8216ee16fc
これまでの、そして現在進行中のパイプラインをすべて見ることができます。
https://gyazo.com/fc5a3a174ad2e3d6b183a70a5c1a619b
進行中のパイプラインをクリックしてみましょう。パイプラインは、各OS、各Pythonバージョンで実行されます。数分待つと結果が表示されます。
https://gyazo.com/20ea442e52f76624bd6e98c7561f92a9
全てのパイプラインが成功しました これでPyPiにパッケージを公開する準備が整いました。
poetryでPyPiにパッケージを公開する
パッケージを公開するには、pyproject.tomlファイルの [tool.poetry] セクションにいくつかの詳細を追加します。
code: 抜粋 pyproject.toml
name = "summarize_dataframe"
version = "0.1.0"
description = "A package to provide summary data about pandas DataFrame"
license = "MIT"
readme = "README.md"
ここでのすべての変数は非常に明確です。これらはパッケージの公開に必要なメタデータです。include変数は、好きなファイルを追加するのに便利です。ここでは、CHANGELOG.md ファイルを追加します。commitizenを覚えていますか?もし覚えていなければ、commitizenと従来のコミットに関する記事を読んでみてください。次のコマンドを使用します。
code: bash
$ cz bump
pyproject.tomlファイルからセマンティックバージョンを表示し、Gitタグを作成するように指示します。このバージョンは、あなたのGitコミットに基づいて更新されます。次に、CHANGELOG.md を作成します。
code: bash
$ cz changelog
$ cat CHANGELOG.md
## Unreleased
## 0.1.0 (2021-04-28)
### Refactor
- correct pylint warnings
- split the function into two: one returning df other for output
### Feat
- implementation of the summary function to summarize dataframe
CHANGELOG.md は、commizenにより生成されたGit履歴に基づいて作成されています。いい感じでしょう?この後は、パッケージの公開に集中しましょう。
code: bash
$ poetry build
Building summarize_dataframe (0.1.0)
- Building sdist
- Built summarize_dataframe-0.1.0.tar.gz
- Building wheel
- Built summarize_dataframe-0.1.0-py3-none-any.whl
これにより、ビルドされたパッケージが配置された dist というフォルダが作成されます。すべてが機能しているかどうかをテストするには、pipを使用します。
注意: この作業は、仮想環境を汚染しないように、仮想環境の外で行ってください。
code: bash
$ pip install path/to/your/package/summarize_dataframe-0.1.0-py3-none-any.whl
ここで、PyPI のアカウントを作成する必要があります。想定される内容を入力し、メールを認証してから、次を実行してください。 code: bash
$ poetry publish
Username: ***********
Password: ***********
Publishing summarize_dataframe (0.1.0) to PyPI
- Uploading summarize_dataframe-0.1.0-py3-none-any.whl 100%
- Uploading summarize_dataframe-0.1.0.tar.gz 100%
このパッケージはオンラインで公開され、コミュニティで共有されています。
https://gyazo.com/777f6960b95476c49b674b2d1c31362f
まとめ
toxは、すべてのユニットテストと検証チェックを自動化するための素晴らしいインターフェースを提供します。poetryを取り巻くエコシステムはより成熟してきており、あまり手間をかけずにtoxと連携するためのソリューションを提供しています。これら2つのソリューションを組み合わせることで、非常に効率的で一貫性のあるCIパイプラインを構築することができます。パイプラインを実行し、異なるOSやPythonのバージョンでパッケージをテストするには、上述のようにGitHub Actionsを活用します。
詩は私たちのアプローチの中心でした。poetryは、プロジェクトの初期化から公開、パッケージや依存関係の管理に至るまで、その使いやすさと有効性を示し、Pythonでプロジェクトを開発する開発者、データサイエンティスト、データエンジニアの生活を間違いなく促進します。
私たちの記事では、優れたソフトウェアエンジニアリングの実践を尊重するために、あなた自身のPythonプロジェクトを構築するために活用できる完全なセットアップを説明しています。
チートシート
tox
tox パイプラインを実行
code: bash
$ tox
poetry
パッケージをビルド
code: bash
$ poetry build
パッケージをPyPIへ公開
code: bash
$ poetry publish